package com.rockbb.common.sso;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.rockbb.common.sso.cookie.SessionCookieHandler;
import com.rockbb.common.sso.cookie.SessionCookies;
import com.rockbb.common.sso.session.BasicSessionFactory;
import com.rockbb.common.sso.session.Session;
import com.rockbb.common.sso.session.SessionConstants;

public class SessionService
{
	private static Logger logger = Logger.getLogger(SessionService.class);

	/*
	 * 在用户登录后, 将user uid绑定至指定session, 同时更新session pool 和 浏览器 cookie
	 */
	public static void login(HttpServletResponse response, String sid, long uuid, int autologin)
	{
		logger.debug("login: sid "+sid + ", uuid "+uuid);
		syncCookie(response, sid);
		BasicSessionFactory.getInstance().updateSessionUser(sid, uuid, autologin);
	}

	/*
	 * 在用户登出后, 同步session pool 和 浏览器 cookie, 其session id和对应的session依然保留在pool中,
	 * 但是session被重置为anonymous session 
	 */
	public static void logout(HttpServletResponse response, String sid)
	{
		syncCookie(response, sid);
		BasicSessionFactory.getInstance().resetSession(sid);
	}

	/**
	 * @return the size of the session pool
	 */
	public static int countAllSessions()
	{
		return BasicSessionFactory.getInstance().countAll();
	}

	/**
	 * 
	 * @return session instances in the session pool
	 */
	public static List<Session> getSessionsByPage(int start, int step)
	{
		int to = start + step;

		Collection<String> keys = BasicSessionFactory.getInstance().getSessionKeys();
		List<String> array = new ArrayList<String>(keys);
		if (start < 0) 
			start = 0;
		else if (start > array.size() - 1) 
			start = array.size() - 1;

		if (to <= start || to < 0 || to > array.size()) to = array.size();

		List<String> slice = array.subList(start, to);

		return BasicSessionFactory.getInstance().getSessions(slice);
	}

	/**
	 * 根据 request 中的cookie, 获取当前访问对应的session. 并通过response, 更新浏览器cookie的时间
	 * 
	 * @param res
	 * @param req
	 * @return
	 */
	public static Session getSession(HttpServletResponse res, HttpServletRequest req)
	{
		SessionCookies cookies = SessionCookieHandler.getCookies(req);
		String sid = cookies.getValue(SessionCookies.KEY_SESSIONID);

		// 从session池中获取session, 注: 当cookie为空时, 不创建新session, 
		// 以免不支持cookie的客户端访问导致大量无效session被生成
		Session session = BasicSessionFactory.getInstance().getSession(
				sid, 
				req.getHeader("User-Agent"), 
				req.getRemoteAddr(), 
				false,						// Allow null
				!cookies.is_empty(),	// Create
				true);						// Update session time 

		if (!cookies.getValue(SessionCookies.KEY_SESSIONID).equalsIgnoreCase(session.getSession_id()))
		{
			cookies.setValue(SessionCookies.KEY_SESSIONID, session.getSession_id());
		}

		// session的有效期由session自身判断, cookie有效期默认设置为最大
		SessionCookieHandler.setCookies(res, cookies, SessionConstants.SESSION_EXPIRE_MAX);

		return session;
	}

	/*
	 * Return null if the session doesn't exist, no cookie operations
	 */
	public static Session getActualSession(String session_id, String browser, String ip, boolean time_update) 
	{
		return BasicSessionFactory.getInstance().getSession(
				session_id, 
				browser, 
				ip, 
				true,						// Allow null
				false,	// Create
				time_update);						// Update session time 
	}

	/**
	 * <p>This is for special cases only, e.g. the session id changed during the user login. If the new session ID
	 * doesn't exist in the session pool, it will return an anonymous session.</p>
	 * 
	 * <p>This method will <b>NOT</b> touch the cookies</p>
	 * 
	 * @param res
	 * @param req
	 * @param newSid
	 * @return Session from the pool, if the sid doesn't exist, it returns an anonymous session 
	 */
	public static Session getSessionWithSid(HttpServletResponse res, HttpServletRequest req, String newSid)
	{
		// Get session from pool by specifying the session id. 
		Session session = BasicSessionFactory.getInstance().getSession(
				newSid, 
				req.getHeader("User-Agent"), 
				req.getRemoteAddr(), 
				false,			// Allow null
				false,			// Create
				true);			// Update session time

		return session;
	}

	/*
	 * 删除session, 并清空其相关的所有cookie
	 */
	public static void deleteSession(HttpServletResponse response, Session session)
	{
		SessionCookieHandler.unSetCookies(response);
		BasicSessionFactory.getInstance().deleteSession(session.getSession_id());
	}

	/**
	 * Clean the session pool, remove the expired sessions
	 * 
	 */
	public static void cleanUp()
	{
		BasicSessionFactory sessionFactory = BasicSessionFactory.getInstance();
		if(System.currentTimeMillis() - SessionConstants.SESSION_CLEAN_INTERVAL*1000L > sessionFactory.getClean_flag())
		{
			sessionFactory.setClean_flag(System.currentTimeMillis());
			sessionFactory.cleanUp();
		}
	}

	/**
	 * 将指定的sid 赋值给浏览器cookie,  并更新cookie时间
	 * 用于: 1.同步session与cookie; 2.切换用户至新session
	 * 
	 * @param response
	 * @param sid
	 */
	public static void syncCookie(HttpServletResponse response, String sid)
	{
		SessionCookies cookies = new SessionCookies();
		cookies.setValue(SessionCookies.KEY_SESSIONID, sid);
		SessionCookieHandler.setCookies(response, cookies, SessionConstants.SESSION_EXPIRE_MAX);
	}
}
